﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml;
using System.Net;
using System.IO;

namespace Marbles.Core.Controls
{
    [ToolboxData("<{0}:FeedViewer runat=server></{0}:FeedViewer>")]
    public class FeedViewer : CompositeControl
    {

        public Table ChildTable
        {
            get
            {
                EnsureChildControls();
                return tbl;
            }
        }

        [Browsable(false), PersistenceMode(PersistenceMode.InnerProperty), TemplateContainer(typeof(FeedTemplateContainer))]
        public ITemplate ItemTemplate { get { return _itemtemplate; } set { _itemtemplate = value; } }
        public virtual string Title { get { object obj = ViewState["title"]; return (obj == null) ? string.Empty : obj.ToString(); } set { ViewState["title"] = value; } }
        public Int32 CharacterWrap { get { object obj = ViewState["wrap"]; return (obj == null) ? 20 : Convert.ToInt32(obj); } set { ViewState["wrap"] = value; } }
        public virtual string Url { get { object obj = ViewState["Url"]; return (obj == null) ? string.Empty : obj.ToString(); } set { ViewState["Url"] = value; } }
        public ScrollBars ScrollBars { get { object obj = ViewState["Scrollbars"]; return (obj == null) ? ScrollBars.None : (ScrollBars)obj; } set { ViewState["Scrollbars"] = value; } }
        private ITemplate _itemtemplate;

        private Table tbl;

        private XmlDocument GetFeedDocument()
        {
            HttpWebRequest request = HttpWebRequest.Create(Url) as HttpWebRequest;
            request.Proxy = Marbles.Core.Settings.SettingsManager.CreateWebProxy();            
            HttpWebResponse response = request.GetResponse() as HttpWebResponse;
            StreamReader sr = new StreamReader(response.GetResponseStream());
            string xml = sr.ReadToEnd().Trim();
            sr.Close();
            response.Close();
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xml);
            return doc;
        }

        private void ApplyScrollStyle()
        {
            switch (ScrollBars)
            {
                case System.Web.UI.WebControls.ScrollBars.Auto: this.Style.Add("overflow", "auto"); break;
                case System.Web.UI.WebControls.ScrollBars.Both: this.Style.Add("overflow", "scroll"); break;
                case System.Web.UI.WebControls.ScrollBars.Horizontal: this.Style.Add("overflow-x", "scroll"); this.Style.Add("overflow-y", "hidden"); break;
                case System.Web.UI.WebControls.ScrollBars.Vertical: this.Style.Add("overflow-x", "hidden"); this.Style.Add("overflow-y", "scroll"); break;
            }
        }

        protected virtual void AddTitleRow()
        {
            TableHeaderRow row = new TableHeaderRow();
            TableHeaderCell cell = new TableHeaderCell();
            row.Cells.Add(cell);
            cell.Text = Title;
            ChildTable.Rows.Add(row);
        }

        protected override void CreateChildControls()
        {
            XmlDocument doc = GetFeedDocument();
            ApplyScrollStyle();
            tbl = new Table();
            tbl.CellPadding = 2;
            tbl.CellSpacing = 0;
            tbl.BorderStyle = System.Web.UI.WebControls.BorderStyle.None;
            tbl.GridLines = GridLines.None;
            this.Controls.Add(tbl);

            if (!string.IsNullOrEmpty(this.Title)) { AddTitleRow(); }

            switch (doc.DocumentElement.Name)
            {
                case "feed":
                    ParseAtomFeed(doc);
                    break;
                case "rss":
                    ParseRSSFeed(doc);
                    break;
            }

        }

        protected virtual TableRow CreateItemRow(string title, string description, DateTime pubdate, string url)
        {
            TableRow row = new TableRow();
            TableCell cell = new TableCell();

            row.Cells.Add(cell);

            if (_itemtemplate == null)
            {
                cell.Text = string.Format("<a href=\"{0}\" title=\"{3} ({4})\" target=\"blank\">{1}</a><br><font size=\"-1\">{2}</font>", url, title, SubStringAtWordBoundary(description, CharacterWrap), description, pubdate.ToShortDateString() + " " + pubdate.ToShortTimeString());
            }
            else
            {
                FeedTemplateContainer container = new FeedTemplateContainer(this);
                ItemTemplate.InstantiateIn(container);
                cell.Controls.Add(container);
                Control Title = container.FindControl("Title");
                Control Description = container.FindControl("Description");

                if (Title != null)
                {
                    if (Title.GetType() == typeof(HyperLink))
                    {
                        ((HyperLink)Title).Text = title;
                        ((HyperLink)Title).NavigateUrl = url;
                        ((HyperLink)Title).ToolTip = description + " (" + pubdate.ToShortDateString() + " " + pubdate.ToShortTimeString() + ")";
                    }

                    if (Title.GetType() == typeof(Label))
                    {
                        ((Label)Title).Text = title;
                    }
                }

                if (Description != null)
                {
                    if (Description.GetType() == typeof(HyperLink))
                    {
                        ((HyperLink)Description).Text = SubStringAtWordBoundary(description, CharacterWrap);
                        ((HyperLink)Description).NavigateUrl = url;
                        ((HyperLink)Description).ToolTip = description + " (" + pubdate.ToShortDateString() + " " + pubdate.ToShortTimeString() + ")";
                    }

                    if (Description.GetType() == typeof(Label))
                    {
                        ((Label)Description).Text = SubStringAtWordBoundary(description, CharacterWrap);
                    }
                }
            }

            return row;
        }

        private string SubStringAtWordBoundary(string value, int limit)
        {
            string value1 = value.Trim();
            if (value1.Length <= limit) { return value1; }
            value1 = value1.Substring(0, limit);
            int index = value1.Length - 1;

            do
            {
                if (Char.IsWhiteSpace(value1, index)) { break; }
                index -= 1;
            }
            while (index >= 0);

            value1 = value1.Substring(0, index).Trim() + "...";
            return value1;
        }

        protected virtual void ParseAtomFeed(XmlDocument doc)
        {
            XmlNodeList list = doc.DocumentElement.GetElementsByTagName("entry");
            XmlNamespaceManager ns = new XmlNamespaceManager(new NameTable());
            ns.AddNamespace(string.Empty, "http://www.w3.org/2005/Atom");
            ns.AddNamespace("atom", "http://www.w3.org/2005/Atom");

            foreach (XmlNode node in list)
            {
                string title = GetNodeValue<string>(node, "//atom:entry//atom:title", ns);
                string description = GetNodeValue<string>(node, "//atom:entry//atom:summary", ns);
                string link = GetNodeValue<string>(node, "//atom:entry//atom:link", ns);
                DateTime pubDate = GetNodeValue<DateTime>(node, "//atom:entry//atom:updated", ns);
                ChildTable.Rows.Add(CreateItemRow(title, description, pubDate, link));
            }
        }

        protected virtual void ParseRSSFeed(XmlDocument doc)
        {
            XmlElement root = doc.DocumentElement.SelectSingleNode("channel") as XmlElement;

            XmlNodeList list = root.GetElementsByTagName("item");

            foreach (XmlNode node in list)
            {
                string title = GetNodeValue<string>(node, "title");
                string description = GetNodeValue<string>(node, "description");
                string link = GetNodeValue<string>(node, "link");
                DateTime pubDate = GetNodeValue<DateTime>(node, "pubDate");
                ChildTable.Rows.Add(CreateItemRow(title, description, pubDate, link));
            }
        }


        private T GetNodeValue<T>(XmlNode node, string key, XmlNamespaceManager ns)
        {
            XmlNode value = node.SelectSingleNode(key, ns);
            if (value == null) { return default(T); }

            return (T)Convert.ChangeType(value.InnerText, typeof(T));
        }

        private T GetNodeValue<T>(XmlNode node, string key)
        {
            XmlNode value = node.SelectSingleNode(key);
            if (value == null) { return default(T); }

            return (T)Convert.ChangeType(value.InnerText, typeof(T));
        }
    }

    public class FeedTemplateContainer : Control, INamingContainer
    {
        private FeedViewer parent;
        public FeedTemplateContainer(FeedViewer parent)
        {
            this.parent = parent;
        }
    }
}
